﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using EnvDTE;
using System.Runtime.Remoting.Messaging;
using Microsoft.VisualStudio.TextTemplating;
using System.IO;
using Microsoft.VisualStudio.Shell.Design;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TemplateWizard;
using MVC4WPF.Automation.Data;

namespace MVC4WPF.Automation.Wizards
{
    public static class WizardUtilityMethods
    {
        /// <summary>
        /// Helper method that will execute a T4 template and return the results from the template.
        /// </summary>
        /// <typeparam name="T">The type of template parameters that will be passed through to the template.</typeparam>
        /// <param name="TemplateFile">The full path to the templatefile.</param>
        /// <param name="TemplateParameters">Data class that holds the paramters that are used by the target template.</param>
        /// <returns></returns>
        public static Data.TransformResults ExecuteTemplate<T>(this IWizard wizard, string TemplateFile, T TemplateParameters)
        {
            //Getting the local threads current context
            CallContext.HostContext = System.Threading.Thread.CurrentContext;

            //Setting the parameters that the template will use
            CallContext.LogicalSetData("TemplateParameters", TemplateParameters);

            //The template host that will be processing the template
            Automation.DefaultTextTemplatingEngineHost host = new DefaultTextTemplatingEngineHost();

            Engine t4engine = new Engine();

            //If the template file can not be found raise an exception.
            if (!System.IO.File.Exists(TemplateFile))
            {
                throw new System.IO.FileNotFoundException(string.Format("The template file '{0}' could not be found.", TemplateFile));
            }


            string template = System.IO.File.ReadAllText(TemplateFile);

            //Setting the path and name of the template file. This is required or the T4 engine will throw an exception. 
            //The file path is used from the template for resource that can not be found.
            host.TemplateFile = TemplateFile;

            string result = t4engine.ProcessTemplate(template, host);

            return new MVC4WPF.Automation.Data.TransformResults { Transformation = result, TransformErrors = host.Errors };
        }

        /// <summary>
        /// Helper method that formats the file path if it uses the local directory syntax of .\
        /// This will inject the default visual studio directory passed in with the wizard.
        /// </summary>
        /// <param name="visualStudioDirectory">The file to the execution point within visual studio.</param>
        /// <param name="parameterFilePath">The file path to be checked.</param>
        /// <returns>Fully qualified file path</returns>
        public static string FormatParameterFilePath(this IWizard wizard, string visualStudioDirectory, string parameterFilePath)
        {
            string resultPath = parameterFilePath;

            if (parameterFilePath.StartsWith(".\\"))
            {
                string updatedPath = parameterFilePath.Replace(".\\", "\\");

                resultPath = string.Format("{0}{1}", visualStudioDirectory, updatedPath);
            }

            return resultPath;
        }

        /// <summary>
        /// Loads the list of MVC contracts based on the base interface type specificed in the provided project.
        /// </summary>
        /// <param name="wizard">Reference to this IWizard</param>
        /// <param name="contractFilter">Type base type of the contracts to filter on</param>
        /// <param name="sourceProject">Project to search in</param>
        /// <returns>A collection of ContractType objects representing the contracts extending the base type</returns>
        public static List<ContractType> LoadContracts(this IWizard wizard, Type contractFilter, Project sourceProject)
        {
            System.IServiceProvider serviceProvider = new ServiceProvider(sourceProject.DTE as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);

            DynamicTypeService typeService = (DynamicTypeService)serviceProvider.GetService(typeof(DynamicTypeService));

            IVsSolution solution = (IVsSolution)serviceProvider.GetService(typeof(SVsSolution));

            return ContractHelper.GetContractsBasedOnContract(solution, typeService, sourceProject, contractFilter);
        }

        /// <summary>
        /// Loads the list of MVC property bags in the provided project.
        /// </summary>
        /// <param name="wizard">Reference to this IWizard</param>
        /// <param name="contractFilter">Type base type of the contracts to filter on</param>
        /// <param name="sourceProject">Project to search in</param>
        /// <returns>A collection of PropertyBagDefinition objects representing the available property bags</returns>
        public static List<PropertyBagDefinition> LoadPropertyBags(this IWizard wizard, Project sourceProject)
        {
            System.IServiceProvider serviceProvider = new ServiceProvider(sourceProject.DTE as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);

            DynamicTypeService typeService = (DynamicTypeService)serviceProvider.GetService(typeof(DynamicTypeService));

            IVsSolution solution = (IVsSolution)serviceProvider.GetService(typeof(SVsSolution));

            return PropertyBagFinder.GetPropertyBags(solution, typeService, sourceProject);
        }

        public static String FormatNamespace(this IWizard wizard, Project projectInfo, string localDirectory)
        {
            if (projectInfo != null)
            {
                string projectPath = projectInfo.Properties.Item("FullPath").Value as string;
                string rootNamespace = projectInfo.Properties.Item("RootNamespace").Value as string;

                if (projectPath == localDirectory)
                {
                    return rootNamespace;
                }

                string appendedPath = localDirectory.Replace(projectPath, "").Replace("\\", ".").TrimEnd(new char[] { '.' });

                return string.Format("{0}.{1}", rootNamespace, appendedPath);

            }
            return null;
        }
    }
}
